package com.zkingsoft.services.impl;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.zkingsoft.actions.common.BaseController;
import com.zkingsoft.codeApi.Attribute;
import com.zkingsoft.codeApi.CodeFile;
import com.zkingsoft.codeApi.Configuration;
import com.zkingsoft.codeApi.DataBaseType;
import com.zkingsoft.codeApi.ModelType;
import com.zkingsoft.codeApi.TableClassModel;
import com.zkingsoft.codeApi.TemplateModel;
import com.zkingsoft.codeApi.Variables;
import com.zkingsoft.generator.Dbconnection;
import com.zkingsoft.plugin.ZipCompressorByAnt;
import com.zkingsoft.plugin.util.DateUtils;
import com.zkingsoft.services.GeneratorService;

import freemarker.template.Template;

@Service(value = "generatorService")
public class GeneratorServiceImpl implements GeneratorService {

	/**
	 * mysql的查询语句，查询数据库中所有的表名
	 */
	@Value("${sql.mysql.serch.tablenames}")
	private String sqlSerchTableNames;
	/**
	 * mysql的查询语句查询指定表中的字段
	 */
	@Value("${sql.mysql.serch.columns}")
	private String sqlSerchColumn;

	@Override
	public Map<String, Object> generator(Configuration configuration) {
		BaseController.log.info("开始生成代码啦。。。。。。");
		Connection connection = Dbconnection.getConnection(configuration);
		configuration = initTableClassConfig(configuration, connection);
		List<CodeFile> codeFiles = generatorFile(configuration);
		return createZipFile(codeFiles);

	}

	/**
	 * 创建要生成的所有文件的模型
	 * 
	 * @param configuration
	 * @return
	 */
	private List<CodeFile> generatorFile(Configuration configuration) {
		List<CodeFile> codeFiles = new ArrayList<CodeFile>();
		Variables variables = new Variables();
		Set<ModelType> modelSet = configuration.getTemplateModels().keySet();

		for (TableClassModel tableClassModel : configuration.getTableClassModels()) {
			for (ModelType modelType : modelSet) {
				TemplateModel templateModel = configuration.getTemplateModels().get(modelType);
				CodeFile codeFile = new CodeFile();
				codeFile.setTableClassModel(tableClassModel);
				codeFile.setTemplateModel(templateModel);
				codeFile.setVariables(variables);
				codeFile.setConfiguration(configuration);
				switch (modelType) {
				case JAVA_BEAN:
					codeFile.setImportList(codeFile.getTableClassModel().getImportList());
					break;
				case MYBATIS_DAO:
					codeFile.setImportList(new HashMap<String, String>());
					codeFile.getImportList().put("bean",
							configuration.getModelPackages().get(0) + "." + tableClassModel.getClassName());
					codeFile.getImportList().put("List", "java.util.List");
					codeFile.getImportList().put("Param", "org.apache.ibatis.annotations.Param");
					codeFile.getImportList().put("PaginationVO", "com.zkingsoft.plugin.pojo.PaginationVO");
					break;
				case MYBATIS_DAO_IMPL:
					TemplateModel daoModel = TemplateModel.getTemplateModel(ModelType.MYBATIS_DAO);
					CodeFile daoFile = new CodeFile();
					daoFile.setTemplateModel(daoModel);
					daoFile.setTableClassModel(tableClassModel);
					codeFile.setDaoInterfase(
							configuration.getModelPackages().get(1) + "." + daoFile.getSimpleFileName());
					break;
				case SERVICE:
					codeFile.setImportList(new HashMap<String, String>());
					codeFile.getImportList().put("bean",
							configuration.getModelPackages().get(0) + "." + tableClassModel.getClassName());
					codeFile.getImportList().put("List", "java.util.List");
					codeFile.getImportList().put("BaseServices", "com.zkingsoft.plugin.pojo.BaseServices");
					codeFile.getImportList().put("PaginationVO", "com.zkingsoft.plugin.pojo.PaginationVO");
					break;
				case SERVICE_IMPL:
					codeFile.setImportList(new HashMap<String, String>());
					codeFile.getImportList().put("bean",
							configuration.getModelPackages().get(0) + "." + tableClassModel.getClassName());

					// 设置注入属性
					TemplateModel daoModel2 = TemplateModel.getTemplateModel(ModelType.MYBATIS_DAO);
					CodeFile daoFile2 = new CodeFile();
					daoFile2.setTemplateModel(daoModel2);
					daoFile2.setTableClassModel(tableClassModel);
					Attribute atribute = new Attribute();
					atribute.setAnnotate("@Autowired");
					atribute.setClassName(daoFile2.getSimpleFileName());
					atribute.setVariableName(daoFile2.getClassVariableName());

					TemplateModel serviceModel = TemplateModel.getTemplateModel(ModelType.SERVICE);
					CodeFile serviceFile = new CodeFile();
					serviceFile.setTemplateModel(serviceModel);
					serviceFile.setTableClassModel(tableClassModel);
					codeFile.getImportList().put("services",
							configuration.getModelPackages().get(3) + "." + serviceFile.getSimpleFileName());
					codeFile.getImportList().put("dao",
							configuration.getModelPackages().get(1) + "." + daoFile2.getSimpleFileName());
					codeFile.getImportList().put("springframework.Service", "org.springframework.stereotype.Service");
					codeFile.getImportList().put("Autowired", "org.springframework.beans.factory.annotation.Autowired");
					codeFile.getImportList().put("List", "java.util.List");
					codeFile.getImportList().put("PaginationVO", "com.zkingsoft.plugin.pojo.PaginationVO");
					// 设置接口
					codeFile.getInterfases().add(serviceFile.getSimpleFileName());
					// 设置注入名称
					codeFile.setInjectionName(serviceFile.getClassVariableName());
					codeFile.setAttribute(atribute);
					break;
				case ACTION:
					TemplateModel serviceModel1 = TemplateModel.getTemplateModel(ModelType.SERVICE);
					CodeFile serviceFile1 = new CodeFile();
					serviceFile1.setTemplateModel(serviceModel1);
					serviceFile1.setTableClassModel(tableClassModel);
					codeFile.setImportList(new HashMap<String, String>());
					codeFile.getImportList().put("bean",
							configuration.getModelPackages().get(0) + "." + tableClassModel.getClassName());
					codeFile.getImportList().put("services",
							configuration.getModelPackages().get(3) + "." + serviceFile1.getSimpleFileName());
					codeFile.getImportList().put("Controller", "org.springframework.stereotype.Controller");
					codeFile.getImportList().put("Resource", "javax.annotation.Resource");
					codeFile.getImportList().put("AjaxResult", "com.zkingsoft.pojo.AjaxResult");
					codeFile.getImportList().put("PaginationVO", "com.zkingsoft.plugin.pojo.PaginationVO");
					codeFile.getImportList().put("SaveRequestToken", "com.zkingsoft.anotations.SaveRequestToken");
					codeFile.getImportList().put("RemoveRequestToken", "com.zkingsoft.anotations.RemoveRequestToken");
					codeFile.getImportList().put("BaseController", "com.zkingsoft.actions.common.BaseController");
					codeFile.getImportList().put("RequestMapping",
							"org.springframework.web.bind.annotation.RequestMapping");
					codeFile.getImportList().put("ResponseBody",
							"org.springframework.web.bind.annotation.ResponseBody");
					break;
				default:
					break;
				}
				codeFiles.add(codeFile);
			}
		}

		CodeFile codeFile = new CodeFile();
		return codeFiles;
	}

	/**
	 * 配置表模型
	 * 
	 * @param configuration
	 * @param connection
	 * @return
	 */
	private Configuration initTableClassConfig(Configuration configuration, Connection connection) {

		List<TableClassModel> tableClassModels = new ArrayList<TableClassModel>();
		for (String tableName : configuration.getTablesName()) {
			if (tableName != null && !tableName.equals("")) {
				String[] paras2 = { tableName, configuration.getDbName() };
				Map map = null;
				try {
					map = Dbconnection.select(connection, sqlSerchColumn, paras2);
					if (map != null) {
						List<Map> rows = (List<Map>) map.get(Dbconnection.RESULT_LIST_KEY);
						TableClassModel tableClassModel = new TableClassModel(configuration, tableName, rows, null);
						tableClassModels.add(tableClassModel);
					}
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
		configuration.setTableClassModels(tableClassModels);
		return configuration;
	}

	/**
	 * 创建zip文件
	 * 
	 * @param configuration
	 * @param dbModel
	 * @return
	 */
	private Map<String, Object> createZipFile(List<CodeFile> codeFiles) {
		try {
			// 创建一个临时文件夹用来存放所有的文件
			// 记录别名
			List<String> alias = new ArrayList<String>();
			// 记录mapper文件
			List<String> mappers = new ArrayList<String>();

			String rootPath = this.getClass().getResource("/").getPath() + "temp" + File.separator
					+ DateUtils.getTimeMark();
			freemarker.template.Configuration cfg = new freemarker.template.Configuration();
			cfg.setLocale(Locale.SIMPLIFIED_CHINESE);
			cfg.setDefaultEncoding("utf-8");
			cfg.setEncoding(Locale.SIMPLIFIED_CHINESE, "utf-8");
			cfg.setEncoding(Locale.SIMPLIFIED_CHINESE,"utf-8");
			for (CodeFile codeFile : codeFiles) {

				Map<String, Object> root = new HashMap<String, Object>();
				root.put("Data", codeFile);
				// 生成代码文件
				BaseController.log.info("生成" + codeFile.getFileName() + "文件...");
				cfg.setDirectoryForTemplateLoading(new File(codeFile.getConfiguration().getUserTempLataHome()));
				// 获取模板（template）
				Template template = cfg.getTemplate(codeFile.getTemplateModel().getTemplateName(), "utf-8");
				// 把文件写入磁盘
				String filePath = rootPath + File.separator
						+ codeFile.getTemplateModel().getSavePath().replace(".", File.separator) + File.separator;
				File file = new File(filePath);
				if (file.getParentFile().exists() && file.exists()) {
					File javaBean = new File(filePath + codeFile.getFileName());
					javaBean.createNewFile();
					BufferedWriter bf = new BufferedWriter(new FileWriter(javaBean));
					template.process(root, bf);
					bf.flush();
					bf.close();
				} else {
					if (file.mkdirs()) {
						File javaBean = new File(filePath + codeFile.getFileName());
						javaBean.createNewFile();
						BufferedWriter bf = new BufferedWriter(new FileWriter(javaBean));
						template.process(root, bf);
						bf.flush();
						bf.close();
					} else {
						BaseController.log.error("创建文件失败" + filePath);
					}
				}
				// 记录别名
				if (codeFile.getTemplateModel().getModelType().equals(ModelType.JAVA_BEAN)) {
					alias.add("<typeAlias alias=\"" + codeFile.getTableClassModel().getClassName() + "\"  type=\""
							+ codeFile.getTemplateModel().getSavePath() + "."
							+ codeFile.getTableClassModel().getClassName() + "\" />");
				} else if (codeFile.getTemplateModel().getModelType().equals(ModelType.MYBATIS_DAO_IMPL)) {
					mappers.add("<mapper resource=\""
							+ codeFile.getTemplateModel().getSavePath().replace(".", File.separator) + File.separator
							+ codeFile.getFileName() + "\"/>");
				}

			}

			// 创建配置文件
			Template template = cfg.getTemplate("mybatis-config.ftl");
			File javaBean = new File(rootPath + File.separator + "mybatis-config.xml");
			javaBean.createNewFile();
			BufferedWriter bf = new BufferedWriter(new FileWriter(javaBean));
			Map<String, Object> root = new HashMap<String, Object>();
			root.put("alias", alias);
			root.put("mappers", mappers);
			template.process(root, bf);
			bf.flush();
			bf.close();

			String zipFileName = DateUtils.getTimeMark();
			// 生成文件完毕读取出文件为压缩流
			fileToZip(rootPath, rootPath, zipFileName);
			File zipFile = new File(rootPath + File.separator + zipFileName + ".zip");
			Map<String, Object> result = new HashMap<String, Object>();
			result.put("zipFile", zipFile);
			result.put("rootPath", rootPath);
			return result;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 获取数据库表名
	 * 
	 * @param configuration
	 * @return
	 */
	@Override
	public List<String> getDBtablsName(Configuration configuration, Connection connection) {
		List<String> tablsName = new ArrayList<String>();
		String[] paras = { configuration.getDbName() };
		Map map = null;
		try {
			// mysql数据库
			if (DataBaseType.MYSQL.equals(configuration.getDataBaseType())) {
				map = Dbconnection.select(connection, sqlSerchTableNames, paras);
			}
			if (map != null) {
				List<Map> rows = (List<Map>) map.get(Dbconnection.RESULT_LIST_KEY);
				for (Map map2 : rows) {
					tablsName.add((String) map2.get("table_name"));
				}
			}
		} catch (SQLException e) {
			BaseController.log.error("查询数据库表名失败");
			e.printStackTrace();
		}
		return tablsName;
	}

	/**
	 * 将存放在sourceFilePath目录下的源文件，打包成fileName名称的zip文件，并存放到zipFilePath路径下
	 * 
	 * @param sourceFilePath
	 *            :待压缩的文件路径
	 * @param zipFilePath
	 *            :压缩后存放路径
	 * @param fileName
	 *            :压缩后文件的名称
	 */
	public static void fileToZip(String sourceFilePath, String zipFilePath, String fileName) {
		ZipCompressorByAnt zca = new ZipCompressorByAnt(zipFilePath + File.separator + fileName + ".zip");
		zca.compressExe(sourceFilePath);
	}

	public String getSqlSerchTableNames() {
		return sqlSerchTableNames;
	}

	public void setSqlSerchTableNames(String sqlSerchTableNames) {
		this.sqlSerchTableNames = sqlSerchTableNames;
	}

	public String getSqlSerchColumn() {
		return sqlSerchColumn;
	}

	public void setSqlSerchColumn(String sqlSerchColumn) {
		this.sqlSerchColumn = sqlSerchColumn;
	}

}
